package com.fr.third.antlr;

import java.util.Hashtable;

import com.fr.third.antlr.collections.AST;
import com.fr.third.antlr.collections.impl.BitSet;
import com.fr.third.antlr.debug.MessageListener;
import com.fr.third.antlr.debug.ParserListener;
import com.fr.third.antlr.debug.ParserMatchListener;
import com.fr.third.antlr.debug.ParserTokenListener;
import com.fr.third.antlr.debug.SemanticPredicateListener;
import com.fr.third.antlr.debug.SyntacticPredicateListener;
import com.fr.third.antlr.debug.TraceListener;

public abstract class Parser {
	protected ParserSharedInputState inputState;
	protected String[] tokenNames;
	protected AST returnAST;
	protected ASTFactory astFactory = null;

	protected Hashtable tokenTypeToASTClassMap = null;

	private boolean ignoreInvalidDebugCalls = false;

	protected int traceDepth = 0;

	public Parser() {
		this(new ParserSharedInputState());
	}

	public Parser(ParserSharedInputState state) {
		this.inputState = state;
	}

	public Hashtable getTokenTypeToASTClassMap() {
		return this.tokenTypeToASTClassMap;
	}

	public void addMessageListener(MessageListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addMessageListener() is only valid if parser built for debugging");
	}

	public void addParserListener(ParserListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addParserListener() is only valid if parser built for debugging");
	}

	public void addParserMatchListener(ParserMatchListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addParserMatchListener() is only valid if parser built for debugging");
	}

	public void addParserTokenListener(ParserTokenListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addParserTokenListener() is only valid if parser built for debugging");
	}

	public void addSemanticPredicateListener(SemanticPredicateListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addSemanticPredicateListener() is only valid if parser built for debugging");
	}

	public void addSyntacticPredicateListener(SyntacticPredicateListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addSyntacticPredicateListener() is only valid if parser built for debugging");
	}

	public void addTraceListener(TraceListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"addTraceListener() is only valid if parser built for debugging");
	}

	public abstract void consume() throws TokenStreamException;

	public void consumeUntil(int tokenType) throws TokenStreamException {
		while ((LA(1) != 1) && (LA(1) != tokenType))
			consume();
	}

	public void consumeUntil(BitSet set) throws TokenStreamException {
		while ((LA(1) != 1) && (!set.member(LA(1))))
			consume();
	}

	protected void defaultDebuggingSetup(TokenStream lexer, TokenBuffer tokBuf) {
	}

	public AST getAST() {
		return this.returnAST;
	}

	public ASTFactory getASTFactory() {
		return this.astFactory;
	}

	public String getFilename() {
		return this.inputState.filename;
	}

	public ParserSharedInputState getInputState() {
		return this.inputState;
	}

	public void setInputState(ParserSharedInputState state) {
		this.inputState = state;
	}

	public String getTokenName(int num) {
		return this.tokenNames[num];
	}

	public String[] getTokenNames() {
		return this.tokenNames;
	}

	public boolean isDebugMode() {
		return false;
	}

	public abstract int LA(int paramInt) throws TokenStreamException;

	public abstract Token LT(int paramInt) throws TokenStreamException;

	public int mark() {
		return this.inputState.input.mark();
	}

	public void match(int t) throws MismatchedTokenException,
			TokenStreamException {
		if (LA(1) != t) {
			throw new MismatchedTokenException(this.tokenNames, LT(1), t,
					false, getFilename());
		}

		consume();
	}

	public void match(BitSet b) throws MismatchedTokenException,
			TokenStreamException {
		if (!b.member(LA(1))) {
			throw new MismatchedTokenException(this.tokenNames, LT(1), b,
					false, getFilename());
		}

		consume();
	}

	public void matchNot(int t) throws MismatchedTokenException,
			TokenStreamException {
		if (LA(1) == t) {
			throw new MismatchedTokenException(this.tokenNames, LT(1), t, true,
					getFilename());
		}

		consume();
	}

	/** @deprecated */
	@Deprecated
	public static void panic() {
		System.err.println("Parser: panic");
		System.exit(1);
	}

	public void removeMessageListener(MessageListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new RuntimeException(
					"removeMessageListener() is only valid if parser built for debugging");
	}

	public void removeParserListener(ParserListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new RuntimeException(
					"removeParserListener() is only valid if parser built for debugging");
	}

	public void removeParserMatchListener(ParserMatchListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new RuntimeException(
					"removeParserMatchListener() is only valid if parser built for debugging");
	}

	public void removeParserTokenListener(ParserTokenListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new RuntimeException(
					"removeParserTokenListener() is only valid if parser built for debugging");
	}

	public void removeSemanticPredicateListener(SemanticPredicateListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"removeSemanticPredicateListener() is only valid if parser built for debugging");
	}

	public void removeSyntacticPredicateListener(SyntacticPredicateListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new IllegalArgumentException(
					"removeSyntacticPredicateListener() is only valid if parser built for debugging");
	}

	public void removeTraceListener(TraceListener l) {
		if (!this.ignoreInvalidDebugCalls)
			throw new RuntimeException(
					"removeTraceListener() is only valid if parser built for debugging");
	}

	public void reportError(RecognitionException ex) {
		System.err.println(ex);
	}

	public void reportError(String s) {
		if (getFilename() == null)
			System.err.println("error: " + s);
		else
			System.err.println(getFilename() + ": error: " + s);
	}

	public void reportWarning(String s) {
		if (getFilename() == null)
			System.err.println("warning: " + s);
		else
			System.err.println(getFilename() + ": warning: " + s);
	}

	public void recover(RecognitionException ex, BitSet tokenSet)
			throws TokenStreamException {
		consume();
		consumeUntil(tokenSet);
	}

	public void rewind(int pos) {
		this.inputState.input.rewind(pos);
	}

	public void setASTFactory(ASTFactory f) {
		this.astFactory = f;
	}

	public void setASTNodeClass(String cl) {
		this.astFactory.setASTNodeType(cl);
	}

	/** @deprecated */
	@Deprecated
	public void setASTNodeType(String nodeType) {
		setASTNodeClass(nodeType);
	}

	public void setDebugMode(boolean debugMode) {
		if (!this.ignoreInvalidDebugCalls)
			throw new RuntimeException(
					"setDebugMode() only valid if parser built for debugging");
	}

	public void setFilename(String f) {
		this.inputState.filename = f;
	}

	public void setIgnoreInvalidDebugCalls(boolean value) {
		this.ignoreInvalidDebugCalls = value;
	}

	public void setTokenBuffer(TokenBuffer t) {
		this.inputState.input = t;
	}

	public void traceIndent() {
		for (int i = 0; i < this.traceDepth; i++)
			System.out.print(' ');
	}

	public void traceIn(String rname) throws TokenStreamException {
		this.traceDepth += 1;
		traceIndent();
		System.out.println("> " + rname + "; LA(1)==" + LT(1).getText()
				+ (this.inputState.guessing > 0 ? " [guessing]" : ""));
	}

	public void traceOut(String rname) throws TokenStreamException {
		traceIndent();
		System.out.println("< " + rname + "; LA(1)==" + LT(1).getText()
				+ (this.inputState.guessing > 0 ? " [guessing]" : ""));

		this.traceDepth -= 1;
	}
}